package com.ordertracker.service;

import com.ordertracker.Application;
import com.ordertracker.Session;
import com.ordertracker.constant.Sex;
import com.ordertracker.dao.GeneralCrudDao;
import com.ordertracker.entity.*;
import com.ordertracker.exception.ValidationException;
import com.ordertracker.persistent.constant.SEX;
import com.ordertracker.persistent.dictionary.*;
import com.ordertracker.persistent.dictionary.Client;
import com.ordertracker.persistent.dictionary.Employee;
import com.ordertracker.persistent.dictionary.Organization;
import com.ordertracker.persistent.dictionary.Person;
import com.ordertracker.persistent.dictionary.Position;
import com.ordertracker.persistent.dictionary.Role;
import com.ordertracker.persistent.dictionary.User;
import com.ordertracker.protocol.CommandMessage;
import com.ordertracker.protocol.UserFullInfo;
import com.ordertracker.to.TransferObjectFactory;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Response;
import javax.xml.bind.JAXBException;
import java.io.StringReader;

@Service(value = "user")
public class UserManager  {

    private static Logger logger = Logger.getLogger(UserManager.class);

    private GeneralCrudDao dao;
    private TransferObjectFactory transferObjectFactory;

    @Resource(name = "crudDao")
    public void setDao(GeneralCrudDao dao) {
        this.dao = dao;
    }

    @Resource(name = "tof")
    public void setTransferObjectFactory(TransferObjectFactory transferObjectFactory) {
        this.transferObjectFactory = transferObjectFactory;
    }

    protected User unmarshal(String obj) throws Exception {
        com.ordertracker.entity.User user = null;
        StringReader sr = new StringReader(obj);
        System.out.println("Position manager: create: "+sr);
        try {
            user = Application.getApplication().getJsonUnmarshaller().unmarshalFromJSON(sr,
                    com.ordertracker.entity.User.class);
        } catch (JAXBException e) {
            logger.error("", e);
        }

        return transferObjectFactory.userFromDTO(user);
    }

    protected String getServiceName() {
        return "user";
    }

    protected void validate(Session session, User msg, ActionType type) throws ValidationException {
        //To change body of implemented methods use File | Settings | File Templates.
    }

    protected Response otherAction(Session session, User obj, ActionType type) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    protected com.ordertracker.entity.User create(Session session, User obj) {
        User user = (User) dao.saveEntity(obj);
        return transferObjectFactory.userToDTO(user);
    }

    protected com.ordertracker.entity.User receive(CommandMessage msg) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    protected com.ordertracker.entity.User delete(Session session, User obj) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    protected com.ordertracker.entity.User update(Session session, User obj) {
        return null;  //To change body of implemented methods use File | Settings | File Templates.
    }

    @Transactional
    @SuppressWarnings("unchecked")
    public UserFullInfo createUser(Session session, UserFullInfo obj)  {

        User user = new User();
        Person person = new Person();
        person.setFirstName(obj.getFirstName());
        person.setLastName(obj.getLastName());
        person.setContactPhone(obj.getContactPhone());
        person.setOld(obj.getOld());
        person.setGender(SEX.valueOf(obj.getGender().getName()));
        Person personPersist = (Person) dao.saveEntity(person);
        user.setName(obj.getName());
        user.setPerson(personPersist);
        user.setEmail(obj.getEmail());
        user.setLogin(obj.getLogin());
        user.setPassword(obj.getPassword());
        user.setDescription(obj.getDescription());
        Role role = (Role) dao.findById(obj.getRole().getId(), Role.class);
        user.setRole(role);
        user.setLocale(obj.getLocale());
        user.setTimezone(obj.getTimezone());
        User usr = (User) dao.saveEntity(user);
        obj.setId(usr.getId());
        obj.setVersion(user.getVersion());

        if (null == obj.getOrganization().getId()) {
            Long clientId = obj.getClient().getId();
            Client client = (Client) dao.findById(clientId, Client.class);
            if (client == null) {
                throw new WebApplicationException(new RuntimeException("Couldn't find client by id: "+clientId),
                        Response.status(Response.Status.BAD_REQUEST).build());
            }
            ClientEmployee clientEmployee = new ClientEmployee(usr, client);
            ClientEmployee ce = (ClientEmployee) dao.saveEntity(clientEmployee);
            obj.setClient(transferObjectFactory.clientToDTO(client));
        } else {
            Organization org = (Organization) dao.findById(obj.getOrganization().getId(), Organization.class);
            Position position  = (Position) dao.findById(obj.getPosition().getId(), Position.class);
            Employee employee = new Employee(user.getRole(), user, org,position);
            Employee eml = (Employee) dao.saveEntity(employee);
            obj.setPosition(transferObjectFactory.positionToDTO(position));
        }

        return obj;
    }

    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    public UserFullInfo getUserFullInfoByID(Long id) {
        UserFullInfo fullInfo = new UserFullInfo();
        User user = (User) dao.findById(id, User.class);
        Person person = user.getPerson();

        fullInfo.setId(user.getId());
        fullInfo.setVersion(user.getVersion());
        fullInfo.setName(user.getName());
        fullInfo.setFirstName(person.getFirstName());
        fullInfo.setLastName(person.getLastName());
        fullInfo.setEmail(user.getEmail());
        fullInfo.setContactPhone(person.getContactPhone());
        fullInfo.setDescription(user.getDescription());
        fullInfo.setLogin(user.getLogin());
        fullInfo.setPassword("");
        fullInfo.setGender(Sex.valueOf(person.getGender().name()));
        fullInfo.setOld(person.getOld());
        fullInfo.setLocale(user.getLocale());
        fullInfo.setTimezone(user.getTimezone());
        Employee employee = getEmployeeByUser(user);
        if (employee != null) {
            fullInfo.setOrganization(transferObjectFactory.organizationToDTO(employee.getOrganization()));
            fullInfo.setPosition(transferObjectFactory.positionToDTO(employee.getPosition()));
        }
        ClientEmployee clientEmployee = getClientEmployeeByUser(user);
        if (clientEmployee != null) {
            fullInfo.setClient(transferObjectFactory.clientToDTO(clientEmployee.getClient()));
        }
        fullInfo.setRole(transferObjectFactory.roleToDTO(user.getRole()));
        return fullInfo;
    }

    @Transactional(readOnly = true)
    @SuppressWarnings("unchecked")
    public com.ordertracker.entity.User getUser(Long id) {
        User user = (User) dao.findById(id, User.class);
        return transferObjectFactory.userToDTO(user);
    }

    @SuppressWarnings("unchecked")
    private ClientEmployee getClientEmployeeByUser(User user) {
        return (ClientEmployee)dao.findEqualByCriteria("user", user, ClientEmployee.class);
    }

    @SuppressWarnings("unchecked")
    private Employee getEmployeeByUser(User user) {
        return  (Employee) dao.findEqualByCriteria("user", user, Employee.class);
    }

}
